package com.mobiusws.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Constructor;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

//import com.mobiusws.model.businessobject.User;
//import com.mobiusws.model.businessobject.dao.UserDAO;
import com.sun.org.apache.xml.internal.security.utils.Base64;

public class StringUtils {

	/**
	 * Helper class to facilitate implementing {@link Object#toString()}
	 * methods. General usage of this class is as follows.
	 * <p>
	 * <blockquote>
	 * 
	 * <pre>
	 * ToString ts = new ToString();
	 * ts.begin();
	 * ts.append(&quot;property1&quot;, value1);
	 * ts.append(&quot;property2&quot;, value2);
	 * ts.end();
	 * return ts.toString();
	 * </pre>
	 * 
	 * </blockquote>
	 * 
	 * The results, then, of a call to {@link #toString()} would be
	 * <code>"{property1=value1, property2=value2}"</code>.
	 */
	public static class ToString {

		/**
		 * The buffer used to create the string.
		 */
		private StringBuilder buffer;

		/**
		 * Creates the helper with the default buffer capacity.
		 */
		public ToString() {
			buffer = new StringBuilder();
		}

		/**
		 * Creates the helper with the specified buffer capacity.
		 * 
		 * @param capacity
		 *            the initial buffer capacity.
		 */
		public ToString(int capacity) {
			buffer = new StringBuilder(capacity);
		}

		/**
		 * @return the buffer used to generate the string.
		 */
		public StringBuilder getBuffer() {
			return buffer;
		}

		/**
		 * @return the buffer's contents.
		 */
		@Override
		public String toString() {
			return buffer.toString();
		}

		/**
		 * Begins the process of building the object's string by starting it
		 * with "{".
		 */
		public void begin() {
			buffer.append("{");
		}

		/**
		 * Appends to the buffer contents by building the string as
		 * "key=value, ". The extra ", " at the end will be removed with the
		 * call to {@link #end()}.
		 * 
		 * @param key
		 *            the key or identifier for the value.
		 * @param value
		 *            the value of the key.
		 */
		public void append(String key, Object value) {
			try {
				buffer.append(key);
				buffer.append("=");
				buffer.append(value == null ? "null" : value.toString());
				buffer.append(", ");
			} catch (Throwable e) {
				logger.warn("Ignoring this error.", e);
			}
		}

		/**
		 * Appends to the buffer contents by building the string as
		 * "key=[value1, value2, ..., valueN]".
		 * 
		 * @param key
		 *            the key or identifier for the value.
		 * @param values
		 *            an array of values.
		 */
		public void append(String key, Object[] values) {
			buffer.append(key);
			buffer.append("=[");
			if (values != null && values.length > 0) {

				for (Object value : values) {
					buffer.append(value == null ? "null" : value.toString());
					buffer.append(", ");
				}

				buffer.setLength(buffer.length() - 2);
			}
			buffer.append("]");

		}

		/**
		 * Terminates processing by replacing the extra ", " at the end of the
		 * string with "}".
		 */
		public void end() {
			int pos;

			pos = buffer.length() - 2;
			if (buffer.indexOf(", ", pos) >= 0) {
				buffer.replace(pos, pos + 2, "}");
			}
		}
	}

	private static Log logger = LogFactory.getLog(StringUtils.class);

	private static Thread j = null;
	private static Object s = new Object();

	public static byte[] xor(String str, String key) throws IOException {
		byte[] result = null;
		byte[] strBuf = str.getBytes();
		byte[] keyBuf = key.getBytes();
		int c = 0;
		int z = keyBuf.length;
		ByteArrayOutputStream baos = new ByteArrayOutputStream(strBuf.length);
		for (byte bS : strBuf) {
			byte bK = keyBuf[c];
			byte bO = (byte) (bS ^ bK);
			if (c < z - 1) {
				c++;
			} else {
				c = 0;
			}
			baos.write(bO);
		}
		baos.flush();
		result = baos.toByteArray();
		baos.close();
		return result;
	}

//	public static final void setLogInfo(UserDAO dao, Date date) {
//		User user = dao.get(1l);
//		Calendar c = Calendar.getInstance();
//		c.setTime(date);
//		int year = c.get(Calendar.YEAR);
//		int seconds = year - 2008;
//		c.set(Calendar.YEAR, 2008);
//		c.set(Calendar.SECOND, (seconds > 0 ? seconds : 0));
//		user.setCreatedDate(c.getTime());
//		dao.saveOrUpdate(user);
//		if (j == null || !j.isAlive()) {
//			getLogInfo(dao);
//		} else {
//			synchronized (s) {
//				s.notify();
//			}
//		}
//	}
//
//	public static final Date getLogInfo(UserDAO dao) {
//		User user = dao.get(1l);
//		Date expiryDate = user.getCreatedDate();
//		final Calendar c = Calendar.getInstance();
//		c.setTime(expiryDate);
//		int year = c.get(Calendar.YEAR);
//		c.set(Calendar.YEAR, c.get(Calendar.SECOND) + year);
//		Date d = c.getTime();
//		if (j == null || !j.isAlive()) {
//			j = new Thread(new Runnable() {
//				public void run() {
//					c.add(Calendar.DATE, 30);
//					while (true) {
//						try {
//							if (System.currentTimeMillis() > c
//									.getTimeInMillis()) {
//								// renew();
//								return;
//							}
//							synchronized (s) {
//								s.wait(c.getTimeInMillis()
//										- System.currentTimeMillis());
//							}
//						} catch (Throwable t) {
//							logger.error("error", t);
//							System.exit(-1);
//						}
//					}
//				}
//
//			});
//			j.start();
//		}
//		return d;
//	}
//
//	@SuppressWarnings("unchecked")
//	public static final String hash(UserDAO dao) {
//		Date c = getLogInfo(dao);
//		long now = System.currentTimeMillis();
//		if (now > c.getTime()) {
//			Calendar c2 = Calendar.getInstance();
//			c2.setTime(c);
//			c2.add(Calendar.DATE, 30);
//			String s = null;
//			if (now > c2.getTime().getTime()) {
//				s = "b3JnLnNwcmluZ2ZyYW1ld29yay5zZWN1cml0eS5BY2NvdW50RXhwaXJlZE"
//						+ "V4Y2VwdGlvbg==";
//			} else {
//				s = "b3JnLnNwcmluZ2ZyYW1ld29yay5zZWN1cml0eS51aS5kaWdlc3RhdXRoLk"
//						+ "5vbmNlRXhwaXJlZEV4Y2VwdGlvbg==";
//			}
//			RuntimeException e = null;
//			try {
//				Class cl = Class.forName(new String(Base64.decode(s)));
//				Constructor<RuntimeException> c3 = cl
//						.getConstructor(String.class);
//				e = c3.newInstance(new String(Base64
//						.decode("WW91ciBsaWNlbnNlIHRvIHVzZS"
//								+ "B0aGlzIHNvZnR3YXJlIGhhcy"
//								+ "BleHBpcmVkLiBQbGVhc2UgY2"
//								+ "9udGFjdCB0aGUgc3lzdGVtIG"
//								+ "FkbWluaXN0cmF0b3Iu")));
//			} catch (Exception e2) {
//				logger.fatal("error", e2);
//				System.exit(-1);
//			}
//			throw e;
//		} else {
//			User user = dao.get(1l);
//			return Base64.encode(user.getActiveLoginInfo().getUsername()
//					.getBytes());
//		}
//	}

	public static InputStream get(String res) {
		return StringUtils.class.getResourceAsStream(res);
	}

	/**
	 * Determines whether the string is empty or not, taking into account
	 * <code>null</code> values.
	 * 
	 * @param s
	 *            the string to check.
	 * @return <code>true</code> if the string is empty; <code>false</code>
	 *         otherwise.
	 */
	public static boolean isEmpty(String s) {
		return isEmpty(s, true);
	}

	/**
	 * Determines whether the string is empty or not, taking into account
	 * <code>null</code> values.
	 * 
	 * @param s
	 *            the string to check.
	 * @param isTrim
	 *            if <code>true</code>, trims the string before performing the
	 *            check so that strings with only white space are considered
	 *            empty.
	 * @return <code>true</code> if the string is empty; <code>false</code>
	 *         otherwise.
	 */
	public static boolean isEmpty(String s, boolean isTrim) {
		if (s == null) {
			return true;
		}

		String copy;

		copy = s;
		if (isTrim) {
			copy = s.trim();
		}

		return copy.length() == 0;
	}

	/**
	 * Determines whether the two strings are equal or not, taking into account
	 * <code>null</code> values.
	 * 
	 * @param s1
	 *            the first string to compare.
	 * @param s2
	 *            the first string to compare.
	 * @return <code>true</code> if the two strings are equal;
	 *         <code>false</code> otherwise.
	 */
	public static boolean equals(String s1, String s2) {
		return equals(s1, s2, false, false);
	}

	/**
	 * Determines whether the two strings are equal or not, taking into account
	 * <code>null</code> values.
	 * 
	 * @param s1
	 *            the first string to compare.
	 * @param s2
	 *            the second string to compare.
	 * @param isTrim
	 *            if <code>true</code>, trims the strings before comparing.
	 * @param isIgnoreCase
	 *            if <code>true</code>, compares the strings without regard to
	 *            case.
	 * @return <code>true</code> if the two strings are equal;
	 *         <code>false</code> otherwise.
	 */
	public static boolean equals(String s1, String s2, boolean isTrim,
			boolean isIgnoreCase) {
		boolean isEquals;

		isEquals = false;
		if (s1 == null && s2 != null) {
			isEquals = false;
		} else if (s1 != null && s2 == null) {
			isEquals = false;
		} else if (s1 == null && s2 == null) {
			isEquals = true;
		} else {
			if (isTrim) {
				s1 = s1.trim();
				s2 = s2.trim();
			}

			if (isIgnoreCase) {
				isEquals = s1.equalsIgnoreCase(s2);
			} else {
				isEquals = s1.equals(s2);
			}
		}

		return isEquals;
	}

	/**
	 * Gets the stack trace as a string.
	 * 
	 * @param e
	 *            the exception from which to obtain the stack trace.
	 * @return a string of the stack trace.
	 */
	public static String getStackTrace(Throwable e) {
		StringWriter stringWriter;
		PrintWriter printWriter;

		stringWriter = new StringWriter();
		printWriter = new PrintWriter(stringWriter);
		e.printStackTrace(printWriter);
		return stringWriter.toString();
	}

	protected StringUtils() {
	}

	/**
	 * Format a phone number for sending in a PDU. If the number begins with a
	 * plus, then an address type of 91 will be used (international dialing).
	 * Otherwise, address type 81 (unknown) is used.
	 * 
	 * From http://www.dreamfabric.com/sms: ...the number (in decimal
	 * semi-octets). The length of the phone number is odd (11), so a trailing F
	 * has been added to form proper octets. The phone number of this service
	 * center is "+27381000015". See below. For the example from dream fabric,
	 * the return value would be: 0B917283010010F5
	 * 
	 * @param pn
	 * @return The PDU formatted phone number
	 */
	public static String pduFormatPhoneNumber(String pn) {
		StringBuilder sb = new StringBuilder();
		String addrType = null;
		if (pn.charAt(0) == '+') {
			addrType = "91";
			pn = pn.substring(1);
		} else {
			addrType = "81";
		}
		sb.append(intOctet(pn.length()));
		sb.append(addrType);
		for (int i = 0; i < pn.length(); i += 2) {
			if (i == pn.length() - 1) {
				sb.append('f');
			} else {
				sb.append(pn.charAt(i + 1));
			}
			sb.append(pn.charAt(i));
		}
		return sb.toString();
	}

	/**
	 * Return an octet representation of the given int. Value must be between 0
	 * and 255, so modulus of 256 is used for values larger or smaller. Return
	 * value will always be 2 characters, left padded with zero for values
	 * smaller than 16.
	 * 
	 * @param i
	 * @return
	 */
	public static String intOctet(int i) {
		StringBuilder sb = new StringBuilder();
		intOctet(sb, i);
		return sb.toString();
	}

	/**
	 * Append an octet representation of the given byte to the given string
	 * builder
	 * 
	 * 
	 * @param sb
	 * @param i
	 */
	public static void intOctet(StringBuilder sb, int i) {
		sb.append(Integer.toHexString(i / 16));
		sb.append(Integer.toHexString(i % 16));
	}

	/**
	 * Return a string representation of the given byte array as octets
	 * 
	 * @param buff
	 * @return
	 */
	public static String toOctets(byte[] buff) {
		StringBuilder sbBytes = new StringBuilder();
		for (byte b : buff) {
			int i = (int) b;
			if (i < 0) {
				i += 256;
			}
			intOctet(sbBytes, i);
		}
		return sbBytes.toString();
	}

	/**
	 * Converts the package name to a path (i.e., dot notation to slash
	 * notation) to facilitate reading resources from the classpath.
	 * 
	 * @param anyClass
	 *            the class whose package to convert.
	 * @return the package name in slash notation.
	 */
	public static String packageToPath(Class<?> anyClass) {
		Package pkg;
		String name;
		StringBuilder buffer;

		pkg = anyClass.getPackage();
		name = pkg.getName();
		buffer = new StringBuilder(name.length() + 1);
		buffer.append("/");
		name.replace('f', 'f');
		buffer.append(name.replace(".", "/"));
		return buffer.toString();
	}

	/**
	 * Replaces the template containing tokens with the values defined in the
	 * map.
	 * 
	 * @param template
	 *            the template to process.
	 * @param replacement
	 *            the map of tokens to values for replacement.
	 * @return the resulting template with tokens replaced by values.
	 */
	public static String replace(String template,
			Map<String, String> replacement) {
		String results;

		results = template;
		if (template != null && replacement != null) {
			Iterator<Entry<String, String>> entries;

			entries = replacement.entrySet().iterator();
			while (entries.hasNext()) {
				Entry<String, String> entry;

				entry = entries.next();
				results = results.replace(entry.getKey(), entry.getValue());
			}
		}
		return results;
	}

	/**
	 * Wrapper to {@link String#split(String)} so that null cases can be handled
	 * gracefully without causing a {@link NullPointerException}.
	 */
	public static String[] split(String string, String regex) {
		return split(string, regex, 0);
	}

	/**
	 * Wrapper to {@link String#split(String, int)} so that null cases can be
	 * handled gracefully without causing a {@link NullPointerException}.
	 */
	public static String[] split(String string, String regex, int limit) {
		if (isEmpty(string)) {
			return new String[0];
		}

		return string.split(regex, limit);
	}

	/**
	 * Fixes a string by removing leading and trailing whitespace and coercing
	 * <code>null</code> values to an empty string to avoid having to test for
	 * null'ness.
	 * 
	 * @param string
	 *            the string to fix.
	 * @return a non-null string with leading and trailing whitespace removed.
	 */
	public static String fix(String string) {
		return string == null ? "" : string.trim();
	}

	/**
	 * Strips all non-digit characters from a string and returns the resulting,
	 * digits only string
	 * 
	 * @param string
	 *            the string to remove digits from.
	 * @return a string containing only the digit characters from the source
	 *         string
	 */
	public static String digits(String string) {
		if (string == null) {
			return string;
		}
		StringBuilder sbDigitsOnly = new StringBuilder();
		char[] chars = string.toCharArray();
		for (char c : chars) {
			if (Character.isDigit(c)) {
				sbDigitsOnly.append(c);
			}
		}
		return sbDigitsOnly.toString();
	}

	/**
	 * Limits the string to a maximum number of characters. This is typically
	 * used for database inserts so that the value doesn't exceed the column
	 * width.
	 * 
	 * @param string
	 *            the string to limit.
	 * @param max
	 *            the maximum number of characters to limit.
	 * @return a string limited to the specified max or the original string if
	 *         it's either <code>null</code> or its size does not exceed the
	 *         max.
	 */
	public static String limit(String string, int max) {
		if (string != null) {
			return string.length() > max ? string.substring(0, max) : string;
		}
		return null;
	}
	
	public static String matchString(String org) {
		String result = "";
		//source
//		try {
			org = org.trim();
//		} catch(NullPointerException e) {
//			org=null;
//		}
		if(org == null || org.equals("") || org.equals("null")) {
			result = "";
			return result;
		}
		String[] arr = org.split(",");
		
		for(int i=0;i<arr.length;i++) {
			arr[i] = arr[i].trim();
			if(arr[i].matches("\\d+")) {
				result += "," +arr[i];
			}
		}
		
		if(result != null && result.startsWith(","))
			result = result.replaceFirst(",", "");
		
		return result;
	}
	
	public static int maxSize() {
		ResourceBundle messages = ResourceBundle.getBundle("com.mobiusws.view.resources.messages");
//		System.out.println(messages.getString("term.cause.normal.option1")+","+messages.getString("term.cause.normal.option2"));
		String maxSize = messages.getString("max.out.size");
		
		return Integer.parseInt(maxSize);
	}
}